package com.summer.common.exceptionHandler;


import com.summer.common.R;
import com.summer.common.exceptionHandler.myException.CategoryServiceException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

import java.sql.SQLIntegrityConstraintViolationException;
import java.util.Arrays;

/**
 * 全局异常处理器
 */
// TODO 默认对含有Controller注解的类进行AOP增强, 参数为要增强的注解。 tip：只要在有这两个注解的类上抛出的异常（包括throw语句和方法上抛出）都会经过此类的异常处理器
@ControllerAdvice(annotations = {Controller.class, RestController.class})
// TODO 只要返回字符串（json）数据就要加此注解
@ResponseBody
@Slf4j
public class GlobalExceptionHandler {

    /**  TODO 1. 注解的参数必须为DuplicateKeyException，除非没有设置系统未知异常捕获方法，因为系统抛出的是DuplicateKeyException异常。
     *       2. 如果参数为SQLIntegrityConstraintViolationException会被Exception（系统未知异常）捕获。
     *    原因：可能因为DuplicateKeyException多级继承了RunTimeException，SQLIntegrityConstraintViolationException没继承
     *         优先级会低于前者，但仍可以用SQLIntegrityConstraintViolationException接收异常对象
     **/
    /**
     *  TODO 唯一约束异常处理, 这样就不用查询数据库校验某个属性是否已存在
     * @param ex 唯一约束异常对象
     * @return 返回R<String>错误信息：唯一约束异常则返回属性值已存在，否则返回未知错误
     */
    @ExceptionHandler(DuplicateKeyException.class)
    public R<String> SQLException(SQLIntegrityConstraintViolationException ex){
        log.info("捕获SQLIntegrityConstraintViolationException异常：{}", ex.getMessage());
        // 1. 处理异常信息
        // 1.1 如果包含“Duplicate entry”则确定是唯一约束异常，返回唯一约束信息
        if(ex.getMessage().contains("Duplicate entry")){
            // 2. 返回唯一约束异常信息
            return R.error(ex.getMessage().split(" ")[2] + " 已存在");
        }
        // 3. 返回未知异常
        return R.error("SQLIntegrityConstraintViolationException的未知异常");
    }

    /**
     * 分类业务层抛出的自定义异常
     * @param ex 获取异常对象
     * @return 返回异常信息
     */
    @ExceptionHandler(CategoryServiceException.class)
    public R<String> RelateOtherTableFiledDeleteException(CategoryServiceException ex){
        log.info("捕获CategoryServiceException异常: {}", ex.getMessage());
        return R.error(ex.getMessage());
    }

    /**
     * 捕获系统未知异常，打印异常信息
     * @param e 获取异常对象
     * @return 返回系统未知异常R<String>
     */
    @ExceptionHandler(Exception.class)
    public R<String> systemUnknownException(Exception e){
        log.info("异常类型：["+e.getClass().getName()+"]"+"\n异常信息如下：");
        e.printStackTrace();
        return R.error("系统未知异常！");
    }
}
